package hhs.poc.activities.scanner.ocr;

import hhs.poc.util.LevenshteinHelper;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;

import com.googlecode.leptonica.android.Binarize;
import com.googlecode.leptonica.android.Convert;
import com.googlecode.leptonica.android.Pix;
import com.googlecode.leptonica.android.ReadFile;
import com.googlecode.leptonica.android.WriteFile;
import com.googlecode.tesseract.android.TessBaseAPI;

/**
 * @author guvin
 * 
 */
public class TesseractOCRScanner extends OCRScanner {

	private TessBaseAPI ocrEngine;
	private Bitmap lastUsedBitmap;

	public TesseractOCRScanner() {
		initTesseract();
	}

	@Override
	public OCRScannerResult doScan(Bitmap bitmap) {

		// Binarize image
		bitmap = binarize(bitmap);
		//bitmap = convertToARGB8888(bitmap);

		// Crop image
		// TODO: Remove hardcoded coordinates
		bitmap = Bitmap.createBitmap(bitmap, 90, 210, 420, 90);
		lastUsedBitmap = bitmap;

		// OCR
		ocrEngine.setImage(bitmap.copy(Bitmap.Config.ARGB_8888, true));

		String ocrResult = ocrEngine.getUTF8Text();

		Department department = predictDepartment(ocrResult);
		int level = getLevel(ocrResult);
		int room = getRoom(ocrResult);

		OCRScannerResult result = new OCRScannerResult(department, level, room,
				ocrResult);

		return result;
	}

	/**
	 * Correct OCR result by guessing which department is the most likely
	 * candidate by comparing the string to the perfect examples.
	 * 
	 * @param ocrResult
	 *            OCR result
	 * @return Department
	 */
	public Department predictDepartment(String ocrResult) {

		ocrResult = ocrResult.toLowerCase();

		Map<Department, Integer> depDistance = new HashMap<Department, Integer>();

		// Check each dep
		String depStr = null;
		for (Department dep : Department.values()) {
			depStr = dep.name().toLowerCase();
			int distance = LevenshteinHelper.getDistance(depStr, ocrResult);

			depDistance.put(dep, distance);
		}

		// Retrieve closest
		int smallest = Integer.MAX_VALUE;
		Department result = null;
		for (Department dep : depDistance.keySet()) {
			int distance = depDistance.get(dep);

			if (distance < smallest) {
				smallest = distance;
				result = dep;
			}
		}

		return result;
	}

	public Bitmap getLastUsedBitmap() {
		return lastUsedBitmap;
	}

	public void release() {
		ocrEngine.end();
	}

	private int[] getIntegers(String ocrResult) {
		int[] ints = new int[2];
		Arrays.fill(ints, 0);

		int dot = ocrResult.indexOf(".");
		if (dot == -1)
			return ints;

		boolean isValid = dot - 1 > 0 && dot + 2 < ocrResult.length();
		if (isValid && Character.isDigit(ocrResult.charAt(dot - 1))
				&& Character.isDigit(ocrResult.charAt(dot + 1))
				&& Character.isDigit(ocrResult.charAt(dot + 2))) {

			int level = Integer.parseInt(ocrResult.charAt(dot - 1) + "");
			int room = Integer.parseInt(ocrResult.charAt(dot + 1) + ""
					+ ocrResult.charAt(dot + 2));
			ints[0] = level;
			ints[1] = room;

		}

		return ints;
	}

	private int getLevel(String ocrResult) {

		int[] ints = getIntegers(ocrResult);
		
		return ints[0];
	}

	private int getRoom(String ocrResult) {

		int[] ints = getIntegers(ocrResult);

		return ints[1];
	}

	private void initTesseract() {
		ocrEngine = new TessBaseAPI();

		ocrEngine.init("/mnt/sdcard/tesseract/", "nld");

		ocrEngine.setVariable(TessBaseAPI.VAR_ACCURACYVSPEED, "100");

		ocrEngine.setVariable("tessedit_char_whitelist",
				"0123456789.slingertpugzakov");
	}

	private Bitmap binarize(Bitmap bitmap) {

		// Convert bitmap to right format if necessary
		bitmap = convertToARGB8888(bitmap);

		// Convert to 8bpp and apply Otsu adapative thresholding
		Pix pix = ReadFile.readBitmap(bitmap);
		pix = Convert.convertTo8(pix);
		pix = Binarize.otsuAdaptiveThreshold(pix);
		bitmap = WriteFile.writeBitmap(pix);
		pix.recycle();

		return bitmap;
	}
	
	private Bitmap convertToARGB8888(Bitmap bitmap) {
		if (bitmap.getConfig() != Config.ARGB_8888) {
			bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
		}
		
		return bitmap;
	}

}
